//
//  CLAudioPlayer.swift
//  clreader
//
//  Created by colin on 2019/3/28.
//  Copyright © 2019 colin. All rights reserved.
//

import UIKit
import AVKit

class CLAudioPlayer: NSObject {
    
    enum Status {
        case loading    //正在加载
        case playing    //正在播放
        case paused     //暂停
        case stopped    //停止
        case ended      //结束
        case error      //错误
    }
    
    static let shared = CLAudioPlayer()
    
    /// 播放器状态
    var status = Observable(Status.stopped)

    /// 当前正在播放的音频
    let current = Observable<CLAudio?>(nil)
    
    /// 播放列表
    var audios = [CLAudio]()
    
    /// 音频控制器
    var controllPanel = CLAudioControlPanel(frame: CGRect.zero)
    
    /// 播放进度
    let progress = Observable(CGFloat(0))
    
    override init() {
        super.init()
        
        self.playerStatusDispose = self.status.observe { [weak self] (new, old) in
            
            // controll panel 状态刷新
            if old != nil {
                self?.controllPanel.reload()
            }
            
            // 加载音频总时间
            if let livePlayer  = self?.liveAudioPlayer ,let liveItem = livePlayer.currentItem , new == .playing {
                self?.mediaTotalTime = TimeInterval(liveItem.duration.value) / TimeInterval(liveItem.duration.timescale)
            }
            
            if new == .ended || new == .error || new == .stopped {
                self?.recoverAudioBackMode()
            }

        }

        self.audioConfigNotification()
        UIApplication.shared.beginReceivingRemoteControlEvents()
        self.configRemoteCommandCenter()
        
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    
    private var liveAudioPlayer:CLPlayer?
    
    // 观察者持有对象
    private var playerStatusDispose:Disposable?
    private var playerItemStatusDispose:Disposable?
    private var playerTimeControlStatusDispose:Disposable?
    private var playerRateDispose:Disposable?
    private var liveAudioPlayerItemNotificationHandle:NSObjectProtocol?
    
    // 当前播放的index
    private var currentIndex:Int? {
        if let currentAudio = self.current.value, let currentIndex = self.audios.index(for: currentAudio) {
            return currentIndex
        } else {
            return nil
        }
    }
    
    ///音频总秒数
    private var mediaTotalTime:TimeInterval = 0
    /// 当前播放的进度，秒
    private var mediaCurrentTime:TimeInterval = 0 {
        didSet {
            if self.mediaTotalTime > 0 {
                self.progress.value = CGFloat(self.mediaCurrentTime / self.mediaTotalTime)
            }
            else {
                self.progress.value = 0
            }
        }
    }

}

extension CLAudioPlayer {
    
    /// 设置播放列表，从第index个开始播放, 默认从第一个开始播放
    func play(audios:[CLAudio],index:Int = 0) {
        
        if audios.isEmpty {
            print("-------播放列表为空")
            return
        }
        
        if index >= audios.count {
            print("index out of bounds")
            return
        }
        
        if self.audios == audios && self.current.value == audios[index] {
            // 播放当前音频，不作操作
            print("播放当前音频，不作操作")
            return
        }

        self.current.value = audios[index]
        self.audios = audios
        
        // 开始加载播放
        self.play()
    }
    
    /// 是否有下一曲
    var hasNext:Bool {
        if let currentIndex_ = self.currentIndex {
            let endIndex = self.audios.count - 1
            if currentIndex_ < endIndex {
                return true
            } else {
                return false
            }
        } else {
            return false
        }
    }
    
    /// 播放下一个
    func playNext() {
        if let currentIndex_ = self.currentIndex, self.hasNext {
            let nextIndex = currentIndex_ + 1
            self.current.value = self.audios[nextIndex]
            self.play()
        }
    }
    
    /// 是否有上一曲
    var hasPre:Bool {
        if let currentIndex_ = self.currentIndex {
            let startIndex = self.audios.startIndex
            if currentIndex_ > startIndex {
                return true
            } else {
                return false
            }
        } else {
            return false
        }
    }
    
    /// 播放上一个
    func playPre() {
        if let currentIndex_ = self.currentIndex, self.hasPre {
            let preIndex = currentIndex_ - 1
            self.current.value = self.audios[preIndex]
            self.play()
        }
    }
    
}

// MARK: - public attribute
extension CLAudioPlayer {
    /// 音频总秒数
    var totalTime:TimeInterval {
        return self.mediaTotalTime
    }
    
    ///当前播放的进度，秒
    var currentTime:TimeInterval {
        return self.mediaCurrentTime
    }
    
}

// MARK: - public method
extension CLAudioPlayer {
    
    /// 开始播放
    func startOrResume() {
        
        self.mediaItemArtwork()
        self.configAudioBackMode()
        
        self.liveAudioPlayer?.play()
        //self.status.value = .playing
    }
    
    /// 暂停播放
    func pause() {
        self.liveAudioPlayer?.pause()
        //self.status.value = .paused
    }
    
    /// 关闭
    func stop() {
        self.clear()
        self.status.value = .stopped
    }
    
    /// 快进快退
    func seek(to time:TimeInterval, completeHandle:((_ complete:Bool)->Void)?) {
        let cmTime = CMTime(seconds: time, preferredTimescale: 1)
        self.liveAudioPlayer?.seek(to: cmTime, completionHandler: { (complete) in
            completeHandle?(complete)
        })
    }
    
}

extension CLAudioPlayer {
    /// 开始播放
    private func play() {
        guard let audio = self.current.value else {
            print("当前没有播放的音频")
            return
        }
        
        //audio item
        guard let audioItem = CLPlayerItem(urlString: audio.url) else {
            print("初始化音频失败")
            return
        }
        
        // 移除上一个资源的观察
        if let notif = self.liveAudioPlayerItemNotificationHandle {
            NotificationCenter.default.removeObserver(notif)
        }
        
        // 音频资源加载观察者
        self.playerItemStatusDispose = audioItem.tlStatus.observe { [weak self] (new, old) in
            switch new {
            case .readyToPlay:
                
                guard let playerItem = self?.liveAudioPlayer?.currentItem as? CLPlayerItem else { return }
                self?.mediaTotalTime = CMTimeGetSeconds(playerItem.duration)
                self?.liveAudioPlayerItemNotificationHandle = NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: playerItem, queue: OperationQueue.main, using: { [weak self] (notif) in
                    
                    // 当前音频播放完成,根据播放模式判断 下一曲，随机，单曲循环
                    self?.liveAudioPlayer?.currentItem?.seek(to: CMTime.zero, completionHandler: nil)
                    
                    if let hasNext_ = self?.hasNext, hasNext_ {
                        // 自动播放下一曲
                        self?.playNext()
                    } else {
                        // 全部播放完成
                        self?.status.value = .ended
                        self?.clear()
                    }
                    
                })
                
                // 直接开始播放
                self?.startOrResume()
            case .failed:
                self?.status.value = .error
            default:break
            }
        }
        
        if let player = self.liveAudioPlayer {
            // 切换音频
            player.replaceCurrentItem(with: audioItem)
        } else {
            // player
            let player = CLPlayer(playerItem: audioItem)
            
            // 播放状态观察者
            if #available(iOS 10.0, *) {
                self.playerTimeControlStatusDispose = player.tlTimeControlStatus.observe { [weak self] (new, old) in
                    if old == nil { return }
                    switch new {
                    case .waitingToPlayAtSpecifiedRate:
                        self?.status.value = .loading
                    case .playing:
                        self?.status.value = .playing
                    case .paused:
                        self?.status.value = .paused
                    default:break
                    }
                }
            } else {
                self.playerRateDispose = player.tlRate.observe { [weak self] (new, old) in
                    if old == nil { return }
                    if new > 0 {
                        self?.status.value = .playing
                    } else {
                        self?.status.value = .paused
                    }
                }
            }
            
            // player 观察者, 1秒调用一次
            let interval = CMTime(seconds: 1.0, preferredTimescale: Int32(NSEC_PER_SEC))
            let queue = DispatchQueue.global()
            player.addPeriodicTimeObserver(forInterval: interval, queue: queue) { [weak self] (time) in
                
                // 当前播放时间
                self?.mediaCurrentTime = CMTimeGetSeconds(time)
                
                // 播放总时间
                if let totalTime = self?.liveAudioPlayer?.currentItem?.duration {
                    self?.mediaTotalTime = CMTimeGetSeconds(totalTime)
                } else {
                    self?.mediaTotalTime = 0
                }
                
                self?.mediaItemArtwork()
                
            }
            
            self.liveAudioPlayer = player
        }
        
    }
    
    /// 清理播放状态
    private func clear() {
        if let livePlayer = self.liveAudioPlayer {
            livePlayer.replaceCurrentItem(with: nil)
            if let notif = self.liveAudioPlayerItemNotificationHandle {
                NotificationCenter.default.removeObserver(notif)
            }
            self.liveAudioPlayer = nil
            //self.current = nil
            //self.status.value = .stopped
        }
    }
}

//MARK:AVAudioSessionInterruptionNotification
extension CLAudioPlayer {
//    @objc private func onAudioSessionEvent(notification:Notification) {
//        if notification.name == Notification.Name.AVAudioSession.interruptionNotification {
//            if let why = notification.userInfo?[AVAudioSessionInterruptionTypeKey] as? UInt , let type = AVAudioSessionInterruptionType(rawValue: why) , type == .began {
//                if self.status^ == .playing {
//                    self.pauseAudio()
//                }
//
//            } else {
//                if self.status^ == .pause {
//                    self.startOrResumeAudio()
//                }
//            }
//        }
//    }
}
